home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / gnulib / dkbtrace / pbmplus / source / ppm / picttopp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-10  |  32.3 KB  |  1,345 lines

  1. /*
  2.  * picttoppm.c -- convert a MacIntosh PICT file to PPM format.
  3.  *
  4.  * Copyright 1989 George Phillips
  5.  *
  6.  * Permission is granted to freely distribute this program in whole or in
  7.  * part provided you don't make money off it, you don't pretend that you
  8.  * wrote it and that this notice accompanies the code.
  9.  *
  10.  * George Phillips <phillips@cs.ubc.ca>
  11.  * Department of Computer Science
  12.  * University of British Columbia
  13.  */
  14.  
  15. #include "ppm.h"
  16.  
  17. /*
  18.  * Typical byte, 2 byte and 4 byte integers.
  19.  */
  20. typedef unsigned char byte;
  21. typedef unsigned short word;
  22. typedef unsigned long longword;
  23.  
  24. /*
  25.  * Data structures for QuickDraw (and hence PICT) stuff.
  26.  */
  27.  
  28. struct Rect {
  29.     word top;
  30.     word left;
  31.     word bottom;
  32.     word right;
  33. };
  34.  
  35. struct pixMap {
  36.     struct Rect Bounds;
  37.     word version;
  38.     word packType;
  39.     longword packSize;
  40.     longword hRes;
  41.     longword vRes;
  42.     word pixelType;
  43.     word pixelSize;
  44.     word cmpCount;
  45.     word cmpSize;
  46.     longword planeBytes;
  47.     longword pmTable;
  48.     longword pmReserved;
  49. };
  50.  
  51. struct ct_entry {
  52.     word red;
  53.     word green;
  54.     word blue;
  55. };
  56.  
  57. static char* stage;
  58. static struct Rect picFrame;
  59. static word* red;
  60. static word* green;
  61. static word* blue;
  62. static word rowlen;
  63. static longword planelen;
  64. static int verbose;
  65.  
  66. struct opdef {
  67.     char* name;
  68.     int len;
  69.     void (*impl)();
  70.     char* description;
  71. };
  72.  
  73. #define WORD_LEN (-1)
  74.  
  75. static void interpret_pict ARGS(( void ));
  76. static void compact_plane ARGS(( word* plane, int planelen ));
  77. static void output_ppm ARGS(( int version ));
  78. static void Opcode_9A ARGS(( void ));
  79. static void BitsRect ARGS(( int version ));
  80. static void BitsRegion ARGS(( int version ));
  81. static void do_bitmap ARGS(( int version, int rowBytes, int is_region ));
  82. static void do_pixmap ARGS(( int version, word rowBytes, int is_region ));
  83. static void blit ARGS((
  84.     struct Rect* srcRect, struct Rect* srcBounds, int srcwid, byte* srcplane,
  85.     int pixSize, struct Rect* dstRect, struct Rect* dstBounds, int dstwid,
  86.     struct ct_entry* colour_map, int mode ));
  87. static byte* unpackbits ARGS(( struct Rect* bounds, word rowBytes, int pixelSize ));
  88. static byte* expand_buf ARGS(( byte* buf, int* len, int bits_per_pixel ));
  89. static void Clip ARGS(( int version ));
  90. static void read_pixmap ARGS(( struct pixMap* p, word* rowBytes ));
  91. static struct ct_entry* read_colour_table ARGS(( void ));
  92. static void BkPixPat ARGS(( int version ));
  93. static void PnPixPat ARGS(( int version ));
  94. static void FillPixPat ARGS(( int version ));
  95. static void read_pattern ARGS(( void ));
  96.  
  97. static void skip_text ARGS(( void ));
  98. static void LongText ARGS(( int version ));
  99. static void DHText ARGS(( int version ));
  100. static void DVText ARGS(( int version ));
  101. static void DHDVText ARGS(( int version ));
  102. static void skip_poly_or_region ARGS(( int version ));
  103. static void LongComment ARGS(( void ));
  104.  
  105. static int rectsamesize ARGS(( struct Rect* r1, struct Rect* r2 ));
  106. static void rectinter ARGS(( struct Rect* r1, struct Rect* r2, struct Rect* r3 ));
  107.  
  108. static void read_rect ARGS(( struct Rect* r ));
  109. static void dump_rect ARGS(( char* s, struct Rect* r ));
  110.  
  111. static word get_op ARGS(( int version ));
  112.  
  113. static longword read_long ARGS(( void ));
  114. static word read_word ARGS(( void ));
  115. static byte read_byte ARGS(( void ));
  116.  
  117. static void skip ARGS(( int n ));
  118. static void read_n ARGS(( int n, char* buf ));
  119.  
  120. /*
  121.  * a table of the first 194(?) opcodes.  The table is too empty.
  122.  *
  123.  * Probably could use an entry specifying if the opcode is valid in version
  124.  * 1, etc.
  125.  */
  126.  
  127. /* for reserved opcodes of known length */
  128. #define res(length) \
  129. { "reserved", (length), NULL, "reserved for Apple use" }
  130.  
  131. /* for reserved opcodes of length determined by a function */
  132. #define resf(skipfunction) \
  133. { "reserved", NA, (skipfunction), "reserved for Apple use" }
  134.  
  135. /* seems like RGB colours are 6 bytes, but Apple say's they're variable */
  136. /* I'll use 6 for now as I don't care that much. */
  137. #define RGB_LEN (6)
  138.  
  139. #define NA (0)
  140.  
  141. static struct opdef optable[] = {
  142. /* 0x00 */    { "NOP", 0, NULL, "nop" },
  143. /* 0x01 */    { "Clip", NA, Clip, "clip" },
  144. /* 0x02 */    { "BkPat", 8, NULL, "background pattern" },
  145. /* 0x03 */    { "TxFont", 2, NULL, "text font (word)" },
  146. /* 0x04 */    { "TxFace", 1, NULL, "text face (byte)" },
  147. /* 0x05 */    { "TxMode", 2, NULL, "text mode (word)" },
  148. /* 0x06 */    { "SpExtra", 4, NULL, "space extra (fixed point)" },
  149. /* 0x07 */    { "PnSize", 4, NULL, "pen size (point)" },
  150. /* 0x08 */    { "PnMode", 2, NULL, "pen mode (word)" },
  151. /* 0x09 */    { "PnPat", 8, NULL, "pen pattern" },
  152. /* 0x0a */    { "FillPat", 8, NULL, "fill pattern" },
  153. /* 0x0b */    { "OvSize", 4, NULL, "oval size (point)" },
  154. /* 0x0c */    { "Origin", 4, NULL, "dh, dv (word)" },
  155. /* 0x0d */    { "TxSize", 2, NULL, "text size (word)" },
  156. /* 0x0e */    { "FgColor", 4, NULL, "foreground color (longword)" },
  157. /* 0x0f */    { "BkColor", 4, NULL, "background color (longword)" },
  158. /* 0x10 */    { "TxRatio", 8, NULL, "numer (point), denom (point)" },
  159. /* 0x11 */    { "Version", 1, NULL, "version (byte)" },
  160. /* 0x12 */    { "BkPixPat", NA, BkPixPat, "color background pattern" },
  161. /* 0x13 */    { "PnPixPat", NA, PnPixPat, "color pen pattern" },
  162. /* 0x14 */    { "FillPixPat", NA, FillPixPat, "color fill pattern" },
  163. /* 0x15 */    { "PnLocHFrac", 2, NULL, "fractional pen position" },
  164. /* 0x16 */    { "ChExtra", 2, NULL, "extra for each character" },
  165. /* 0x17 */    res(0),
  166. /* 0x18 */    res(0),
  167. /* 0x19 */    res(0),
  168. /* 0x1a */    { "RGBFgCol", RGB_LEN, NULL, "RGB foreColor" },
  169. /* 0x1b */    { "RGBBkCol", RGB_LEN, NULL, "RGB backColor" },
  170. /* 0x1c */    { "HiliteMode", 0, NULL, "hilite mode flag" },
  171. /* 0x1d */    { "HiliteColor", RGB_LEN, NULL, "RGB hilite color" },
  172. /* 0x1e */    { "DefHilite", 0, NULL, "Use default hilite color" },
  173. /* 0x1f */    { "OpColor", RGB_LEN, NULL, "RGB OpColor for arithmetic modes" },
  174. /* 0x20 */    { "Line", 8, NULL, "pnLoc (point), newPt (point)" },
  175. /* 0x21 */    { "LineFrom", 4, NULL, "newPt (point)" },
  176. /* 0x22 */    { "ShortLine", 6, NULL, "pnLoc (point, dh, dv (-128 .. 127))" },
  177. /* 0x23 */    { "ShortLineFrom", 2, NULL, "dh, dv (-128 .. 127)" },
  178. /* 0x24 */    res(WORD_LEN),
  179. /* 0x25 */    res(WORD_LEN),
  180. /* 0x26 */    res(WORD_LEN),
  181. /* 0x27 */    res(WORD_LEN),
  182. /* 0x28 */    { "LongText", NA, LongText, "txLoc (point), count (0..255), text" },
  183. /* 0x29 */    { "DHText", NA, DHText, "dh (0..255), count (0..255), text" },
  184. /* 0x2a */    { "DVText", NA, DVText, "dv (0..255), count (0..255), text" },
  185. /* 0x2b */    { "DHDVText", NA, DHDVText, "dh, dv (0..255), count (0..255), text" },
  186. /* 0x2c */    res(WORD_LEN),
  187. /* 0x2d */    res(WORD_LEN),
  188. /* 0x2e */    res(WORD_LEN),
  189. /* 0x2f */    res(WORD_LEN),
  190. /* 0x30 */    { "frameRect", 8, NULL, "rect" },
  191. /* 0x31 */    { "paintRect", 8, NULL, "rect" },
  192. /* 0x32 */    { "eraseRect", 8, NULL, "rect" },
  193. /* 0x33 */    { "invertRect", 8, NULL, "rect" },
  194. /* 0x34 */    { "fillRect", 8, NULL, "rect" },
  195. /* 0x35 */    res(8),
  196. /* 0x36 */    res(8),
  197. /* 0x37 */    res(8),
  198. /* 0x38 */    { "frameSameRect", 0, NULL, "rect" },
  199. /* 0x39 */    { "paintSameRect", 0, NULL, "rect" },
  200. /* 0x3a */    { "eraseSameRect", 0, NULL, "rect" },
  201. /* 0x3b */    { "invertSameRect", 0, NULL, "rect" },
  202. /* 0x3c */    { "fillSameRect", 0, NULL, "rect" },
  203. /* 0x3d */    res(0),
  204. /* 0x3e */    res(0),
  205. /* 0x3f */    res(0),
  206. /* 0x40 */    { "frameRRect", 8, NULL, "rect" },
  207. /* 0x41 */    { "paintRRect", 8, NULL, "rect" },
  208. /* 0x42 */    { "eraseRRect", 8, NULL, "rect" },
  209. /* 0x43 */    { "invertRRect", 8, NULL, "rect" },
  210. /* 0x44 */    { "fillRRrect", 8, NULL, "rect" },
  211. /* 0x45 */    res(8),
  212. /* 0x46 */    res(8),
  213. /* 0x47 */    res(8),
  214. /* 0x48 */    { "frameSameRRect", 0, NULL, "rect" },
  215. /* 0x49 */    { "paintSameRRect", 0, NULL, "rect" },
  216. /* 0x4a */    { "eraseSameRRect", 0, NULL, "rect" },
  217. /* 0x4b */    { "invertSameRRect", 0, NULL, "rect" },
  218. /* 0x4c */    { "fillSameRRect", 0, NULL, "rect" },
  219. /* 0x4d */    res(0),
  220. /* 0x4e */    res(0),
  221. /* 0x4f */    res(0),
  222. /* 0x50 */    { "frameOval", 8, NULL, "rect" },
  223. /* 0x51 */    { "paintOval", 8, NULL, "rect" },
  224. /* 0x52 */    { "eraseOval", 8, NULL, "rect" },
  225. /* 0x53 */    { "invertOval", 8, NULL, "rect" },
  226. /* 0x54 */    { "fillOval", 8, NULL, "rect" },
  227. /* 0x55 */    res(8),
  228. /* 0x56 */    res(8),
  229. /* 0x57 */    res(8),
  230. /* 0x58 */    { "frameSameOval", 0, NULL, "rect" },
  231. /* 0x59 */    { "paintSameOval", 0, NULL, "rect" },
  232. /* 0x5a */    { "eraseSameOval", 0, NULL, "rect" },
  233. /* 0x5b */    { "invertSameOval", 0, NULL, "rect" },
  234. /* 0x5c */    { "fillSameOval", 0, NULL, "rect" },
  235. /* 0x5d */    res(0),
  236. /* 0x5e */    res(0),
  237. /* 0x5f */    res(0),
  238. /* 0x60 */    { "frameArc", 12, NULL, "rect, startAngle, arcAngle" },
  239. /* 0x61 */    { "paintArc", 12, NULL, "rect, startAngle, arcAngle" },
  240. /* 0x62 */    { "eraseArc", 12, NULL, "rect, startAngle, arcAngle" },
  241. /* 0x63 */    { "invertArc", 12, NULL, "rect, startAngle, arcAngle" },
  242. /* 0x64 */    { "fillArc", 12, NULL, "rect, startAngle, arcAngle" },
  243. /* 0x65 */    res(12),
  244. /* 0x66 */    res(12),
  245. /* 0x67 */    res(12),
  246. /* 0x68 */    { "frameSameArc", 4, NULL, "rect, startAngle, arcAngle" },
  247. /* 0x69 */    { "paintSameArc", 4, NULL, "rect, startAngle, arcAngle" },
  248. /* 0x6a */    { "eraseSameArc", 4, NULL, "rect, startAngle, arcAngle" },
  249. /* 0x6b */    { "invertSameArc", 4, NULL, "rect, startAngle, arcAngle" },
  250. /* 0x6c */    { "fillSameArc", 4, NULL, "rect, startAngle, arcAngle" },
  251. /* 0x6d */    res(4),
  252. /* 0x6e */    res(4),
  253. /* 0x6f */    res(4),
  254. /* 0x70 */    { "framePoly", NA, skip_poly_or_region, "poly" },
  255. /* 0x71 */    { "paintPoly", NA, skip_poly_or_region, "poly" },
  256. /* 0x72 */    { "erasePoly", NA, skip_poly_or_region, "poly" },
  257. /* 0x73 */    { "invertPoly", NA, skip_poly_or_region, "poly" },
  258. /* 0x74 */    { "fillPoly", NA, skip_poly_or_region, "poly" },
  259. /* 0x75 */    resf(skip_poly_or_region),
  260. /* 0x76 */    resf(skip_poly_or_region),
  261. /* 0x77 */    resf(skip_poly_or_region),
  262. /* 0x78 */    { "frameSamePoly", 0, NULL, "poly (NYI)" },
  263. /* 0x79 */    { "paintSamePoly", 0, NULL, "poly (NYI)" },
  264. /* 0x7a */    { "eraseSamePoly", 0, NULL, "poly (NYI)" },
  265. /* 0x7b */    { "invertSamePoly", 0, NULL, "poly (NYI)" },
  266. /* 0x7c */    { "fillSamePoly", 0, NULL, "poly (NYI)" },
  267. /* 0x7d */    res(0),
  268. /* 0x7e */    res(0),
  269. /* 0x7f */    res(0),
  270. /* 0x80 */    { "frameRgn", NA, skip_poly_or_region, "region" },
  271. /* 0x81 */    { "paintRgn", NA, skip_poly_or_region, "region" },
  272. /* 0x82 */    { "eraseRgn", NA, skip_poly_or_region, "region" },
  273. /* 0x83 */    { "invertRgn", NA, skip_poly_or_region, "region" },
  274. /* 0x84 */    { "fillRgn", NA, skip_poly_or_region, "region" },
  275. /* 0x85 */    resf(skip_poly_or_region),
  276. /* 0x86 */    resf(skip_poly_or_region),
  277. /* 0x87 */    resf(skip_poly_or_region),
  278. /* 0x88 */    { "frameSameRgn", 0, NULL, "region (NYI)" },
  279. /* 0x89 */    { "paintSameRgn", 0, NULL, "region (NYI)" },
  280. /* 0x8a */    { "eraseSameRgn", 0, NULL, "region (NYI)" },
  281. /* 0x8b */    { "invertSameRgn", 0, NULL, "region (NYI)" },
  282. /* 0x8c */    { "fillSameRgn", 0, NULL, "region (NYI)" },
  283. /* 0x8d */    res(0),
  284. /* 0x8e */    res(0),
  285. /* 0x8f */    res(0),
  286. /* 0x90 */    { "BitsRect", NA, BitsRect, "copybits, rect clipped" },
  287. /* 0x91 */    { "BitsRgn", NA, BitsRegion, "copybits, rgn clipped" },
  288. /* 0x92 */    res(WORD_LEN),
  289. /* 0x93 */    res(WORD_LEN),
  290. /* 0x94 */    res(WORD_LEN),
  291. /* 0x95 */    res(WORD_LEN),
  292. /* 0x96 */    res(WORD_LEN),
  293. /* 0x97 */    res(WORD_LEN),
  294. /* 0x98 */    { "PackBitsRect", NA, BitsRect, "packed copybits, rect clipped" },
  295. /* 0x99 */    { "PackBitsRgn", NA, BitsRegion, "packed copybits, rgn clipped" },
  296. /* 0x9a */    { "Opcode_9A", NA, Opcode_9A, "the mysterious opcode 9A" },
  297. /* 0x9b */    res(WORD_LEN),
  298. /* 0x9c */    res(WORD_LEN),
  299. /* 0x9d */    res(WORD_LEN),
  300. /* 0x9e */    res(WORD_LEN),
  301. /* 0x9f */    res(WORD_LEN),
  302. /* 0xa0 */    { "ShortComment", 2, NULL, "kind (word)" },
  303. /* 0xa1 */    { "LongComment", NA, LongComment, "kind (word), size (word), data" }
  304. };
  305.  
  306. static int align = 0;
  307. static FILE* ifp;
  308.  
  309. void
  310. main(argc, argv)
  311. int argc;
  312. char* argv[];
  313. {
  314.     int argn;
  315.     char* usage = "[-verbose] [pictfile]";
  316.  
  317.     ppm_init( &argc, argv );
  318.  
  319.     argn = 1;
  320.     verbose = 0;
  321.  
  322.     if (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
  323.         if (pm_keymatch(argv[argn], "-verbose", 2))
  324.             verbose = 1;
  325.         else
  326.             pm_usage(usage);
  327.         ++argn;
  328.     }
  329.  
  330.     if (argn < argc) {
  331.         ifp = pm_openr(argv[argn]);
  332.         ++argn;
  333.     } else
  334.         ifp = stdin;
  335.  
  336.     if (argn != argc)
  337.         pm_usage(usage);
  338.  
  339.     stage = "Reading 512 byte header";
  340.     skip(512);
  341.  
  342.     interpret_pict();
  343.     exit(0);
  344. }
  345.  
  346. static void
  347. interpret_pict()
  348. {
  349.     byte ch;
  350.     word picSize;
  351.     word opcode;
  352.     word len;
  353.     int version;
  354.  
  355.     stage = "Reading picture size";
  356.     picSize = read_word();
  357.  
  358.     if (verbose)
  359.         pm_message("picture size = %d (0x%x)", picSize, picSize);
  360.  
  361.     stage = "reading picture frame";
  362.     read_rect(&picFrame);
  363.  
  364.     if (verbose) {
  365.         dump_rect("Picture frame:", &picFrame);
  366.         pm_message("Picture size is %d x %d",
  367.             picFrame.right - picFrame.left,
  368.             picFrame.bottom - picFrame.top);
  369.     }
  370.  
  371.     /* allocation is same for version 1 or version 2.  We are super-duper
  372.      * wasteful of memory for version 1 picts.  Someday, we'll separate
  373.      * things and only allocate a byte per pixel for version 1 (or heck,
  374.      * even only a bit, but that would require even more extra work).
  375.      */
  376.  
  377.     rowlen = picFrame.right - picFrame.left;
  378.     planelen = rowlen * (picFrame.bottom - picFrame.top);
  379.     if ((red = (word*)malloc(planelen * sizeof(word))) == NULL ||
  380.         (green = (word*)malloc(planelen * sizeof(word))) == NULL ||
  381.         (blue = (word*)malloc(planelen * sizeof(word))) == NULL)
  382.  
  383.         pm_error("not enough memory to hold picture");
  384.  
  385.     while ((ch = read_byte()) == 0)
  386.         ;
  387.     if (ch != 0x11)
  388.         pm_error("No version number");
  389.  
  390.     switch (read_byte()) {
  391.     case 1:
  392.         version = 1;
  393.         break;
  394.     case 2:
  395.         if (read_byte() != 0xff)
  396.             pm_error("can only do version 2, subcode 0xff");
  397.         version = 2;
  398.         break;
  399.     default:
  400.         pm_error("Unknown version");
  401.     }
  402.  
  403.     if (verbose)
  404.         pm_message("PICT version %d", version);
  405.  
  406.     while((opcode = get_op(version)) != 0xff) {
  407.         if (opcode < 0xa2) {
  408.             if (verbose) {
  409.                 stage = optable[opcode].name;
  410.                 if (!strcmp(stage, "reserved"))
  411.                     pm_message("reserved opcode=0x%x", opcode);
  412.                 else
  413.                     pm_message("%s", stage = optable[opcode].name);
  414.             }
  415.  
  416.             if (optable[opcode].impl != NULL)
  417.                 (*optable[opcode].impl)(version);
  418.             else if (optable[opcode].len >= 0)
  419.                 skip(optable[opcode].len);
  420.             else switch (optable[opcode].len) {
  421.             case WORD_LEN:
  422.                 len = read_word();
  423.                 skip(len);
  424.                 break;
  425.             default:
  426.                 pm_error("can't do length of %d",
  427.                     optable[opcode].len);
  428.             }
  429.         }
  430.         else if (opcode == 0xc00) {
  431.             if (verbose)
  432.                 pm_message("HeaderOp");
  433.             stage = "HeaderOp";
  434.             skip(24);
  435.         }
  436.         else if (opcode >= 0xa2 && opcode <= 0xaf) {
  437.             stage = "skipping reserved";
  438.             if (verbose)
  439.                 pm_message("%s 0x%x", stage, opcode);
  440.             skip(read_word());
  441.         }
  442.         else if (opcode >= 0xb0 && opcode <= 0xcf) {
  443.             /* just a reserved opcode, no data */
  444.             if (verbose)
  445.                 pm_message("reserved 0x%x", opcode);
  446.         }
  447.         else if (opcode >= 0xd0 && opcode <= 0xfe) {
  448.             stage = "skipping reserved";
  449.             if (verbose)
  450.                 pm_message("%s 0x%x", stage, opcode);
  451.             skip(read_long());
  452.         }
  453.         else if (opcode >= 0x100 && opcode <= 0x7fff) {
  454.             stage = "skipping reserved";
  455.             if (verbose)
  456.                 pm_message("%s 0x%x", stage, opcode);
  457.             skip((opcode >> 7) & 255);
  458.         }
  459.         else if (opcode >= 0x8000 && opcode <= 0x80ff) {
  460.             /* just a reserved opcode */
  461.             if (verbose)
  462.                 pm_message("reserved 0x%x", opcode);
  463.         }
  464.         else if (opcode >= 8100 && opcode <= 0xffff) {
  465.             stage = "skipping reserved";
  466.             if (verbose)
  467.                 pm_message("%s 0x%x", stage, opcode);
  468.             skip(read_long());
  469.         }
  470.         else
  471.             pm_error("can't handle opcode of %x", opcode);
  472.     }
  473.     output_ppm(version);
  474. }
  475.  
  476. static void
  477. compact_plane(plane, planelen)
  478. register word* plane;
  479. register int planelen;
  480. {
  481.     register byte* p;
  482.  
  483.     for (p = (byte*)plane; planelen-- > 0; )
  484.         *p++ = (*plane++ >> 8) & 255;
  485. }
  486.  
  487. static void
  488. output_ppm(version)
  489. int version;
  490. {
  491.     int width;
  492.     int height;
  493.     word test;
  494.     int offset1;
  495.     register char* r;
  496.     register char* g;
  497.     register char* b;
  498.     pixel* pixelrow;
  499.     register pixel* pP;
  500.     int row;
  501.     register int col;
  502.  
  503.     /* determine byte order */
  504.     test = 0x0001;
  505.     offset1 = *((char*)&test);
  506.  
  507.     stage = "writing PPM";
  508.  
  509.     width = picFrame.right - picFrame.left;
  510.     height = picFrame.bottom - picFrame.top;
  511.     r = (char*) red;
  512.     compact_plane((word*) r, width * height);
  513.     g = (char*) green;
  514.     compact_plane((word*) g, width * height);
  515.     b = (char*) blue;
  516.     compact_plane((word*) b, width * height);
  517.  
  518.     ppm_writeppminit(stdout, width, height, (pixval) 255, 0 );
  519.     pixelrow = ppm_allocrow(width);
  520.     for (row = 0; row < height; ++row) {
  521.         for (col = 0, pP = pixelrow; col < width;
  522.              ++col, ++pP, ++r, ++g, ++b) {
  523.             PPM_ASSIGN(*pP, *r, *g, *b);
  524.         }
  525.  
  526.         ppm_writeppmrow(stdout, pixelrow, width, (pixval) 255, 0 );
  527.     }
  528.     pm_close(stdout);
  529. }
  530.  
  531. /*
  532.  * This could use read_pixmap, but I'm too lazy to hack read_pixmap.
  533.  */
  534.  
  535. static void
  536. Opcode_9A()
  537. {
  538. #ifdef DUMP
  539.     FILE *fp = fopen("data", "w");
  540.     int ch;
  541.     if (fp == NULL) exit(1);
  542.     while ((ch = fgetc(ifp)) != EOF) fputc(ch, fp);
  543.     exit(0);
  544. #else
  545.     struct pixMap    p;
  546.     struct Rect        srcRect;
  547.     struct Rect        dstRect;
  548.     byte*            pm;
  549.     int                pixwidth;
  550.     word            mode;
  551.  
  552.     /* skip fake len, and fake EOF */
  553.     skip(4);
  554.     read_word();    /* version */
  555.     read_rect(&p.Bounds);
  556.     pixwidth = p.Bounds.right - p.Bounds.left;
  557.     p.packType = read_word();
  558.     p.packSize = read_long();
  559.     p.hRes = read_long();
  560.     p.vRes = read_long();
  561.     p.pixelType = read_word();
  562.     p.pixelSize = read_word();
  563.     p.pixelSize = read_word();
  564.     p.cmpCount = read_word();
  565.     p.cmpSize = read_word();
  566.     p.planeBytes = read_long();
  567.     p.pmTable = read_long();
  568.     p.pmReserved = read_long();
  569.  
  570.     if (p.pixelSize == 16)
  571.         pixwidth *= 2;
  572.     else if (p.pixelSize == 32)
  573.         pixwidth *= 3;
  574.  
  575.     read_rect(&srcRect);
  576.     if (verbose)
  577.         dump_rect("source rectangle:", &srcRect);
  578.  
  579.     read_rect(&dstRect);
  580.     if (verbose)
  581.         dump_rect("destination rectangle:", &dstRect);
  582.  
  583.     mode = read_word();
  584.     if (verbose)
  585.         pm_message("mode = %x", mode);
  586.  
  587.     pm = unpackbits(&p.Bounds, 0, p.pixelSize);
  588.  
  589.     blit(&srcRect, &(p.Bounds), pixwidth, pm, p.pixelSize,
  590.          &dstRect, &picFrame, rowlen,
  591.          NULL,
  592.          mode);
  593.  
  594.     free(pm);
  595. #endif
  596. }
  597.  
  598. static void
  599. BitsRect(version)
  600. int version;
  601. {
  602.     word rowBytes;
  603.  
  604.     stage = "Reading rowBytes for bitsrect";
  605.     rowBytes = read_word();
  606.  
  607.     if (verbose)
  608.         pm_message("rowbytes = 0x%x (%d)", rowBytes, rowBytes & 0x7fff);
  609.  
  610.     if (rowBytes & 0x8000)
  611.         do_pixmap(version, rowBytes, 0);
  612.     else
  613.         do_bitmap(version, rowBytes, 0);
  614. }
  615.  
  616. static void
  617. BitsRegion(version)
  618. int version;
  619. {
  620.     word rowBytes;
  621.  
  622.     stage = "Reading rowBytes for bitsregion";
  623.     rowBytes = read_word();
  624.  
  625.     if (rowBytes & 0x8000)
  626.         do_pixmap(version, rowBytes, 1);
  627.     else
  628.         do_bitmap(version, rowBytes, 1);
  629. }
  630.  
  631. static void
  632. do_bitmap(version, rowBytes, is_region)
  633. int version;
  634. int rowBytes;
  635. int is_region;
  636. {
  637.     struct Rect Bounds;
  638.     struct Rect srcRect;
  639.     struct Rect dstRect;
  640.     word mode;
  641.     byte* pm;
  642.     static struct ct_entry colour_table[] = { {65535L, 65535L, 65535L}, {0, 0, 0} };
  643.  
  644.     read_rect(&Bounds);
  645.     read_rect(&srcRect);
  646.     read_rect(&dstRect);
  647.     mode = read_word();
  648.  
  649.     if (is_region)
  650.         skip_poly_or_region(version);
  651.  
  652.     stage = "unpacking rectangle";
  653.  
  654.     pm = unpackbits(&Bounds, rowBytes, 1);
  655.  
  656.     blit(&srcRect, &Bounds, Bounds.right - Bounds.left, pm, 8,
  657.          &dstRect, &picFrame, rowlen,
  658.          colour_table,
  659.          mode);
  660.  
  661.     free(pm);
  662. }
  663.  
  664. #if __STDC__
  665. static void
  666. do_pixmap( int version, word rowBytes, int is_region )
  667. #else /*__STDC__*/
  668. static void
  669. do_pixmap(version, rowBytes, is_region)
  670. int version;
  671. word rowBytes;
  672. int is_region;
  673. #endif /*__STDC__*/
  674. {
  675.     word mode;
  676.     struct pixMap p;
  677.     word pixwidth;
  678.     byte* pm;
  679.     struct ct_entry* colour_table;
  680.     struct Rect srcRect;
  681.     struct Rect dstRect;
  682.  
  683.     read_pixmap(&p, NULL);
  684.  
  685.     pixwidth = p.Bounds.right - p.Bounds.left;
  686.  
  687.     if (verbose)
  688.         pm_message("%d x %d rectangle", pixwidth,
  689.             p.Bounds.bottom - p.Bounds.top);
  690.  
  691.     colour_table = read_colour_table();
  692.  
  693.     read_rect(&srcRect);
  694.  
  695.     if (verbose)
  696.         dump_rect("source rectangle:", &srcRect);
  697.  
  698.     read_rect(&dstRect);
  699.  
  700.     if (verbose)
  701.         dump_rect("destination rectangle:", &dstRect);
  702.  
  703.     mode = read_word();
  704.  
  705.     if (verbose)
  706.         pm_message("mode = %x", mode);
  707.  
  708.     if (is_region)
  709.         skip_poly_or_region(version);
  710.  
  711.     stage = "unpacking rectangle";
  712.  
  713.     pm = unpackbits(&p.Bounds, rowBytes, p.pixelSize);
  714.  
  715.     blit(&srcRect, &(p.Bounds), pixwidth, pm, 8,
  716.          &dstRect, &picFrame, rowlen,
  717.          colour_table,
  718.          mode);
  719.  
  720.     free(colour_table);
  721.     free(pm);
  722. }
  723.  
  724. static void
  725. blit(srcRect, srcBounds, srcwid, srcplane, pixSize, dstRect, dstBounds, dstwid, colour_map, mode)
  726. struct Rect* srcRect;
  727. struct Rect* srcBounds;
  728. int srcwid;
  729. byte* srcplane;
  730. int pixSize;
  731. struct Rect* dstRect;
  732. struct Rect* dstBounds;
  733. int dstwid;
  734. struct ct_entry* colour_map;
  735. int mode;
  736. {
  737.     struct Rect clipsrc;
  738.     struct Rect clipdst;
  739.     register byte* src;
  740.     register word* reddst;
  741.     register word* greendst;
  742.     register word* bluedst;
  743.     register int i;
  744.     register int j;
  745.     int dstoff;
  746.     int xsize;
  747.     int ysize;
  748.     int srcadd;
  749.     int dstadd;
  750.     struct ct_entry* ct;
  751.     int pkpixsize;
  752.  
  753.     /* almost got it.  clip source rect with source bounds.
  754.      * clip dest rect with dest bounds.
  755.      * If they're not the same size - die!
  756.      * (it would require zeroing some area!)
  757.      * co-ordinate translations are actually done!
  758.      */
  759.     rectinter(srcBounds, srcRect, &clipsrc);
  760.     rectinter(dstBounds, dstRect, &clipdst);
  761.  
  762.     if (verbose) {
  763.         dump_rect("copying from:", &clipsrc);
  764.         dump_rect("to:          ", &clipdst);
  765.     }
  766.  
  767.     if (!rectsamesize(&clipsrc, &clipdst))
  768.         pm_message("warning, rectangles of different sizes after clipping!");
  769.  
  770.  
  771.     /* lots of assumptions about 8 bits per component, chunky bits, etc! */
  772.     /* :-( :-( */
  773.  
  774.     pkpixsize = 1;
  775.     if (pixSize == 16)
  776.         pkpixsize = 2;
  777.  
  778.     src = srcplane + (clipsrc.top - srcBounds->top) * srcwid +
  779.         (clipsrc.left - srcBounds->left) * pkpixsize;
  780.     dstoff = (clipdst.top - dstBounds->top) * dstwid +
  781.         (clipdst.left - dstBounds->left);
  782.  
  783.     reddst = red + dstoff;
  784.     greendst = green + dstoff;
  785.     bluedst = blue + dstoff;
  786.  
  787.     xsize = clipsrc.right - clipsrc.left;
  788.     ysize = clipsrc.bottom - clipsrc.top;
  789.     srcadd = srcwid - xsize * pkpixsize;
  790.     dstadd = dstwid - xsize;
  791.  
  792.     switch (pixSize) {
  793.     case 8:
  794.         for (i = 0; i < ysize; ++i) {
  795.             for (j = 0; j < xsize; ++j) {
  796.                 ct = colour_map + *src++;
  797.                 *reddst++ = ct->red;
  798.                 *greendst++ = ct->green;
  799.                 *bluedst++ = ct->blue;
  800.             }
  801.             src += srcadd;
  802.             reddst += dstadd;
  803.             greendst += dstadd;
  804.             bluedst += dstadd;
  805.         }
  806.         break;
  807.     case 16:
  808.         for (i = 0; i < ysize; ++i) {
  809.             for (j = 0; j < xsize; ++j) {
  810.                 *reddst++ = (*src & 0x7c) << 9;
  811.                 *greendst = (*src++ & 3) << 14;
  812.                 *greendst++ |= (*src & 0xe0) << 6;
  813.                 *bluedst++ = (*src++ & 0x1f) << 11;
  814.             }
  815.             src += srcadd;
  816.             reddst += dstadd;
  817.             greendst += dstadd;
  818.             bluedst += dstadd;
  819.         }
  820.         break;
  821.     case 32:
  822.         srcadd = (srcwid / 3) - xsize;
  823.         for (i = 0; i < ysize; ++i) {
  824.             for (j = 0; j < xsize; ++j)
  825.                 *reddst++ = *src++ << 8;
  826.  
  827.             reddst += dstadd;
  828.             src += srcadd;
  829.  
  830.             for (j = 0; j < xsize; ++j)
  831.                 *greendst++ = *src++ << 8;
  832.  
  833.             greendst += dstadd;
  834.             src += srcadd;
  835.  
  836.             for (j = 0; j < xsize; ++j)
  837.                 *bluedst++ = *src++ << 8;
  838.  
  839.             bluedst += dstadd;
  840.             src += srcadd;
  841.         }
  842.     }
  843. }
  844.  
  845. #if __STDC__
  846. static byte*
  847. unpackbits( struct Rect* bounds, word rowBytes, int pixelSize )
  848. #else /*__STDC__*/
  849. static byte*
  850. unpackbits(bounds, rowBytes, pixelSize)
  851. struct Rect* bounds;
  852. word rowBytes;
  853. int pixelSize;
  854. #endif /*__STDC__*/
  855. {
  856.     byte* linebuf;
  857.     byte* pm;
  858.     byte* pm_ptr;
  859.     register int i,j,k,l;
  860.     word pixwidth;
  861.     int linelen;
  862.     int len;
  863.     byte* bytepixels;
  864.     int buflen;
  865.     int pkpixsize;
  866.  
  867.     if (pixelSize <= 8)
  868.         rowBytes &= 0x7fff;
  869.  
  870.     stage = "unpacking packbits";
  871.  
  872.     pixwidth = bounds->right - bounds->left;
  873.  
  874.     pkpixsize = 1;
  875.     if (pixelSize == 16) {
  876.         pkpixsize = 2;
  877.         pixwidth *= 2;
  878.     }
  879.     else if (pixelSize == 32)
  880.         pixwidth *= 3;
  881.     
  882.     if (rowBytes == 0)
  883.         rowBytes = pixwidth;
  884.  
  885.     /* we're sloppy and allocate some extra space because we can overshoot
  886.      * by as many as 8 bytes when we unpack the raster lines.  Really, I
  887.      * should be checking to see if we go over the scan line (it is
  888.      * possbile) and complain of a corrupt file.  That fix is more complex
  889.      * (and probably costly in CPU cycles) and will have to come later.
  890.      */
  891.     if ((pm = (byte*)malloc((pixwidth * (bounds->bottom - bounds->top) + 8) * sizeof(byte))) == NULL)
  892.         pm_error("no mem for packbits rectangle");
  893.  
  894.     /* Sometimes we get rows with length > rowBytes.  I'll allocate some
  895.      * extra for slop and only die if the size is _way_ out of wack.
  896.      */
  897.     if ((linebuf = (byte*)malloc(rowBytes + 100)) == NULL)
  898.         pm_error("can't allocate memory for line buffer");
  899.  
  900.     if (rowBytes < 8) {
  901.         /* ah-ha!  The bits aren't actually packed.  This will be easy */
  902.         for (i = 0; i < bounds->bottom - bounds->top; i++) {
  903.             pm_ptr = pm + i * pixwidth;
  904.             read_n(buflen = rowBytes, (char*) linebuf);
  905.             bytepixels = expand_buf(linebuf, &buflen, pixelSize);
  906.             for (j = 0; j < buflen; j++)
  907.                 *pm_ptr++ = *bytepixels++;
  908.         }
  909.     }
  910.     else {
  911.         for (i = 0; i < bounds->bottom - bounds->top; i++) {
  912.             pm_ptr = pm + i * pixwidth;
  913.             if (rowBytes > 250 || pixelSize > 8)
  914.                 linelen = read_word();
  915.             else
  916.                 linelen = read_byte();
  917.  
  918.             if (verbose)
  919.                 pm_message("linelen: %d", linelen);
  920.  
  921.             if (linelen > rowBytes) {
  922.                 pm_message("linelen > rowbytes! (%d > %d) at line %d",
  923.                     linelen, rowBytes, i);
  924.             }
  925.  
  926.             read_n(linelen, (char*) linebuf);
  927.  
  928.             for (j = 0; j < linelen; ) {
  929.                 if (linebuf[j] & 0x80) {
  930.                     len = ((linebuf[j] ^ 255) & 255) + 2;
  931.                     buflen = pkpixsize;
  932.                     bytepixels = expand_buf(linebuf + j+1, &buflen, pixelSize);
  933.                     for (k = 0; k < len; k++) {
  934.                         for (l = 0; l < buflen; l++)
  935.                             *pm_ptr++ = *bytepixels++;
  936.                         bytepixels -= buflen;
  937.                     }
  938.                     j += 1 + pkpixsize;
  939.                 }
  940.                 else {
  941.                     len = (linebuf[j] & 255) + 1;
  942.                     buflen = len * pkpixsize;
  943.                     bytepixels = expand_buf(linebuf + j+1, &buflen, pixelSize);
  944.                     for (k = 0; k < buflen; k++)
  945.                         *pm_ptr++ = *bytepixels++;
  946.                     j += len * pkpixsize + 1;
  947.                 }
  948.             }
  949.         }
  950.     }
  951.  
  952.     free(linebuf);
  953.  
  954.     return(pm);
  955. }
  956.  
  957. static byte*
  958. expand_buf(buf, len, bits_per_pixel)
  959. byte* buf;
  960. int* len;
  961. int bits_per_pixel;
  962. {
  963.     static byte pixbuf[256 * 8];
  964.     register byte* src;
  965.     register byte* dst;
  966.     register int i;
  967.  
  968.     src = buf;
  969.     dst = pixbuf;
  970.  
  971.     switch (bits_per_pixel) {
  972.     case 8:
  973.     case 16:
  974.     case 32:
  975.         return(buf);
  976.     case 4:
  977.         for (i = 0; i < *len; i++) {
  978.             *dst++ = (*src >> 4) & 15;
  979.             *dst++ = *src++ & 15;
  980.         }
  981.         *len *= 2;
  982.         break;
  983.     case 2:
  984.         for (i = 0; i < *len; i++) {
  985.             *dst++ = (*src >> 6) & 3;
  986.             *dst++ = (*src >> 4) & 3;
  987.             *dst++ = (*src >> 2) & 3;
  988.             *dst++ = *src++ & 3;
  989.         }
  990.         *len *= 4;
  991.         break;
  992.     case 1:
  993.         for (i = 0; i < *len; i++) {
  994.             *dst++ = (*src >> 7) & 1;
  995.             *dst++ = (*src >> 6) & 1;
  996.             *dst++ = (*src >> 5) & 1;
  997.             *dst++ = (*src >> 4) & 1;
  998.             *dst++ = (*src >> 3) & 1;
  999.             *dst++ = (*src >> 2) & 1;
  1000.             *dst++ = (*src >> 1) & 1;
  1001.             *dst++ = *src++ & 1;
  1002.         }
  1003.         *len *= 8;
  1004.         break;
  1005.     default:
  1006.         pm_error("bad bits per pixel in expand_buf");
  1007.     }
  1008.     return(pixbuf);
  1009. }
  1010.  
  1011. static void
  1012. Clip(version)
  1013. int version;
  1014. {
  1015.     skip(read_word() - 2);
  1016. }
  1017.  
  1018. static void
  1019. read_pixmap(p, rowBytes)
  1020. struct pixMap* p;
  1021. word* rowBytes;
  1022. {
  1023.     stage = "getting pixMap header";
  1024.  
  1025.     if (rowBytes != NULL)
  1026.         *rowBytes = read_word();
  1027.  
  1028.     read_rect(&p->Bounds);
  1029.     p->version = read_word();
  1030.     p->packType = read_word();
  1031.     p->packSize = read_long();
  1032.     p->hRes = read_long();
  1033.     p->vRes = read_long();
  1034.     p->pixelType = read_word();
  1035.     p->pixelSize = read_word();
  1036.     p->cmpCount = read_word();
  1037.     p->cmpSize = read_word();
  1038.     p->planeBytes = read_long();
  1039.     p->pmTable = read_long();
  1040.     p->pmReserved = read_long();
  1041.  
  1042.     if (verbose) {
  1043.         pm_message("pixelType: %d", p->pixelType);
  1044.         pm_message("pixelSize: %d", p->pixelSize);
  1045.         pm_message("cmpCount:  %d", p->cmpCount);
  1046.         pm_message("cmpSize:   %d", p->cmpSize);
  1047.     }
  1048.  
  1049.     if (p->pixelType != 0)
  1050.         pm_error("sorry, I only do chunky format");
  1051.     if (p->cmpCount != 1)
  1052.         pm_error("sorry, cmpCount != 1");
  1053.     if (p->pixelSize != p->cmpSize)
  1054.         pm_error("oops, pixelSize != cmpSize");
  1055. }
  1056.  
  1057. static struct ct_entry*
  1058. read_colour_table()
  1059. {
  1060.     longword ctSeed;
  1061.     word ctFlags;
  1062.     word ctSize;
  1063.     word val;
  1064.     int i;
  1065.     struct ct_entry* colour_table;
  1066.  
  1067.     stage = "getting color table info";
  1068.  
  1069.     ctSeed = read_long();
  1070.     ctFlags = read_word();
  1071.     ctSize = read_word();
  1072.  
  1073.     if (verbose) {
  1074.         pm_message("ctSeed:  %d", ctSeed);
  1075.         pm_message("ctFlags: %d", ctFlags);
  1076.         pm_message("ctSize:  %d", ctSize);
  1077.     }
  1078.  
  1079.     stage = "reading colour table";
  1080.  
  1081.     if ((colour_table = (struct ct_entry*) malloc(sizeof(struct ct_entry) * (ctSize + 1))) == NULL)
  1082.         pm_error("no memory for colour table");
  1083.  
  1084.     for (i = 0; i <= ctSize; i++) {
  1085.         if ((val = read_word()) > ctSize)
  1086.             pm_error("pixel value greater than colour table size");
  1087.         /* seems that if we have a device colour table, the val is
  1088.          * always zero, so I assume we allocate up the list of colours.
  1089.          */
  1090.         if (ctFlags & 0x8000)
  1091.             val = i;
  1092.         colour_table[val].red = read_word();
  1093.         colour_table[val].green = read_word();
  1094.         colour_table[val].blue = read_word();
  1095.  
  1096.         if (verbose)
  1097.             pm_message("%d: [%d,%d,%d]", val,
  1098.                 colour_table[val].red,
  1099.                 colour_table[val].green,
  1100.                 colour_table[val].blue, 0);
  1101.     }
  1102.  
  1103.     return(colour_table);
  1104. }
  1105.  
  1106. /* these 3 do nothing but skip over their data! */
  1107. static void
  1108. BkPixPat(version)
  1109. int version;
  1110. {
  1111.     read_pattern();
  1112. }
  1113.  
  1114. static void
  1115. PnPixPat(version)
  1116. int version;
  1117. {
  1118.     read_pattern();
  1119. }
  1120.  
  1121. static void
  1122. FillPixPat(version)
  1123. int version;
  1124. {
  1125.     read_pattern();
  1126. }
  1127.  
  1128. /* this just skips over a version 2 pattern.  Probabaly will return
  1129.  * a pattern in the fabled complete version.
  1130.  */
  1131. static void
  1132. read_pattern()
  1133. {
  1134.     word PatType;
  1135.     word rowBytes;
  1136.     struct pixMap p;
  1137.     byte* pm;
  1138.     struct ct_entry* ct;
  1139.  
  1140.     stage = "Reading a pattern";
  1141.  
  1142.     PatType = read_word();
  1143.  
  1144.     switch (PatType) {
  1145.     case 2:
  1146.         skip(8); /* old pattern data */
  1147.         skip(5); /* RGB for pattern */
  1148.         break;
  1149.     case 1:
  1150.         skip(8); /* old pattern data */
  1151.         read_pixmap(&p, &rowBytes);
  1152.         ct = read_colour_table();
  1153.         pm = unpackbits(&p.Bounds, rowBytes, p.pixelSize);
  1154.         free(pm);
  1155.         free(ct);
  1156.         break;
  1157.     default:
  1158.         pm_error("unknown pattern type in read_pattern");
  1159.     }
  1160. }
  1161.  
  1162. /* more stubs for text output */
  1163.  
  1164. static void
  1165. skip_text()
  1166. {
  1167.     skip(read_byte());
  1168. }
  1169.  
  1170. static void
  1171. LongText(version)
  1172. int version;
  1173. {
  1174.     skip(4);
  1175.     skip_text();
  1176. }
  1177.  
  1178. static void
  1179. DHText(version)
  1180. int version;
  1181. {
  1182.     skip(1);
  1183.     skip_text();
  1184. }
  1185.  
  1186. static void
  1187. DVText(version)
  1188. int version;
  1189. {
  1190.     skip(1);
  1191.     skip_text();
  1192. }
  1193.  
  1194. static void
  1195. DHDVText(version)
  1196. int version;
  1197. {
  1198.     skip(2);
  1199.     skip_text();
  1200. }
  1201.  
  1202. static void
  1203. skip_poly_or_region(version)
  1204. int version;
  1205. {
  1206.     stage = "skipping polygon or region";
  1207.     skip(read_word() - 2);
  1208. }
  1209.  
  1210. static void
  1211. LongComment()
  1212. {
  1213.     stage = "skipping longword comment";
  1214.  
  1215.     skip(2);
  1216.     skip(read_word());
  1217. }
  1218.  
  1219. static int
  1220. rectequal(r1, r2)
  1221. struct Rect* r1;
  1222. struct Rect* r2;
  1223. {
  1224.     return(r1->top == r2->top &&
  1225.            r1->bottom == r2->bottom &&
  1226.            r1->left == r2->left &&
  1227.            r1->right == r2->right);
  1228. }
  1229.  
  1230. static int
  1231. rectsamesize(r1, r2)
  1232. struct Rect* r1;
  1233. struct Rect* r2;
  1234. {
  1235.     return(r1->right - r1->left == r2->right - r2->left &&
  1236.            r1->bottom - r1->top == r2->bottom - r2->top);
  1237. }
  1238.  
  1239. static void
  1240. rectinter(r1, r2, r3)
  1241. struct Rect* r1;
  1242. struct Rect* r2;
  1243. struct Rect* r3;
  1244. {
  1245.     r3->left = max(r1->left, r2->left);
  1246.     r3->top = max(r1->top, r2->top);
  1247.     r3->right = min(r1->right, r2->right);
  1248.     r3->bottom = min(r1->bottom, r2->bottom);
  1249. }
  1250.  
  1251. static void
  1252. read_rect(r)
  1253. struct Rect* r;
  1254. {
  1255.     r->top = read_word();
  1256.     r->left = read_word();
  1257.     r->bottom = read_word();
  1258.     r->right = read_word();
  1259. }
  1260.  
  1261. static void
  1262. dump_rect(s, r)
  1263. char* s;
  1264. struct Rect* r;
  1265. {
  1266.     pm_message("%s (%d,%d) (%d,%d)",
  1267.         s, r->left, r->top, r->right, r->bottom);
  1268. }
  1269.  
  1270. /*
  1271.  * All data in version 2 is 2-byte word aligned.  Odd size data
  1272.  * is padded with a null.
  1273.  */
  1274. static word
  1275. get_op(version)
  1276. int version;
  1277. {
  1278.     if ((align & 1) && version == 2) {
  1279.         stage = "aligning for opcode";
  1280.         read_byte();
  1281.     }
  1282.  
  1283.     stage = "reading opcode";
  1284.  
  1285.     if (version == 1)
  1286.         return(read_byte());
  1287.     else
  1288.         return(read_word());
  1289. }
  1290.  
  1291. static longword
  1292. read_long()
  1293. {
  1294.     word i;
  1295.  
  1296.     i = read_word();
  1297.     return((i << 16) | read_word());
  1298. }
  1299.  
  1300. static word
  1301. read_word()
  1302. {
  1303.     byte b;
  1304.  
  1305.     b = read_byte();
  1306.  
  1307.     return((b << 8) | read_byte());
  1308. }
  1309.  
  1310. static byte
  1311. read_byte()
  1312. {
  1313.     int c;
  1314.  
  1315.     if ((c = fgetc(ifp)) == EOF)
  1316.         pm_error("EOF / read error while %s", stage);
  1317.  
  1318.     ++align;
  1319.     return(c & 255);
  1320. }
  1321.  
  1322. static void
  1323. skip(n)
  1324. int n;
  1325. {
  1326.     static byte buf[1024];
  1327.  
  1328.     align += n;
  1329.  
  1330.     for (; n > 0; n -= 1024)
  1331.         if (fread(buf, n > 1024 ? 1024 : n, 1, ifp) != 1)
  1332.             pm_error("EOF / read error while %s", stage);
  1333. }
  1334.  
  1335. static void
  1336. read_n(n, buf)
  1337. int n;
  1338. char* buf;
  1339. {
  1340.     align += n;
  1341.  
  1342.     if (fread(buf, n, 1, ifp) != 1)
  1343.         pm_error("EOF / read error while %s", stage);
  1344. }
  1345.